package com.lancoo.ccas52;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.lancoo.ccas52.entity.*;
import com.lancoo.ccas52.mapper.*;
import com.lancoo.ccas52.pojo.dto.RedisStudentOptionalClass;
import com.lancoo.ccas52.service.*;
import com.lancoo.ccas52.service.impl.StudentServiceImpl;
import com.lancoo.ccas52.util.BatchInsert;
import org.apache.commons.lang3.RandomUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @ClassName StudentVirtualData
 * @Description TODO
 * @Author quin
 * @Date 2023/10/25 11:52
 */
@SpringBootTest
public class StudentVirtualData {

    @Resource
    private MajorMapper majorMapper;
    @Resource
    private PlanTeachingMapper planTeachingMapper;
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private PlanTeachingCourseSegmentMapper planTeachingCourseSegmentMapper;
    @Resource
    private PlanTeachingStudentMapper planTeachingStudentMapper;
    @Resource
    private TeachingClassMapper teachingClassMapper;
    @Resource
    private TeachingClassService teachingClassService;
    @Resource
    private StudentMapper studentMapper;

    @Resource
    private TaskInfoService taskInfoService;
    @Resource
    private TaskToGradeService taskToGradeService;
    @Resource
    private CssTaskInfoService cssTaskInfoService;
    @Resource
    private CssTaskRoundService cssTaskRoundService;
    @Resource
    private CssRangeService cssRangeService;
    @Resource
    private StudentServiceImpl studentService;


    /**
     * 简化选课并发测试 ，保证接口完整执行。数据设计如下规则
     * 1、教学班数 == 课程库数量
     * 2、每个教学计划包含课程库全部课程
     * 3、选课容量 == 学生总数
     * 4、压测10min，每次测试都需要清空缓存.
     * qps * 60 * 10 < 4 * COLLEGE_NUM * MAJOR_NUM * STUDENT_NUM * COURSE_NUM = 1600000
     *
     */

    public static final int TASK_ID = 1;
    //选课容量
    public static final int CLASS_NUM = Integer.MAX_VALUE;
    public static final String CAMPUS_NAME = "本部";
    public static final String COURSE_TYPE = "数学理论";
    //学院数量
    public static final int COLLEGE_NUM = 10;
    //每个学院对应专业数
    public static final int MAJOR_NUM = 4;
    //每个年级、专业对应学生数。 学生总数为 4 * COLLEGE_NUM * MAJOR_NUM * STUDENT_NUM
    public static final int STUDENT_NUM = 100;
    //课程库课程数量
    public static final int COURSE_NUM = 100;
    //每个课程生成教学班数量。 教学班总数为 COURSE_NUM * TEACHING_CLASS_NUM
    public static final int TEACHING_CLASS_NUM = 1;

    public static Map<String, String> gradeMap = new HashMap<>();
    public static Map<String, String> collegeMap = new HashMap<>();
    public static List<MajorVirtual> majorVirtualList = new ArrayList<>();
    public static Map<PlanTeaching, List<Student>> planStudentVirtualMap = new HashMap<>();

    public static List<Major> majorList = new ArrayList<>();
    public static List<PlanTeaching> planTeachingList = new ArrayList<>();
    public static List<Student> studentList = new ArrayList<>();
    public static List<Course> courseList = new ArrayList<>();
    public static List<PlanTeachingCourseSegment> planTeachingCourseSegmentList = new ArrayList<>();
    public static List<PlanTeachingStudent> planTeachingStudentList = new ArrayList<>();
    public static List<TeachingClass> teachingClassList = new ArrayList<>();

    public static class MajorVirtual {
        public String majorId;
        public String majorName;
        public String collegeId;
        public String collegeName;
    }

    static {
        gradeMap.put("2021", "2021级");
        gradeMap.put("2022", "2022级");
        gradeMap.put("2023", "2023级");
        gradeMap.put("2024", "2024级");

        //生成学院
        for (int i = 0; i < COLLEGE_NUM; i++) {
            collegeMap.put("C-" + (i + 1), "学院" + (i + 1));
        }
        //生成专业
        collegeMap.forEach((collegeId, collegeName) -> {
            for (int i = 0; i < MAJOR_NUM; i++) {
                MajorVirtual major = new MajorVirtual();
                major.majorId = collegeId + "-M-" + (i + 1);
                major.majorName = collegeName + "-专业" + (i + 1);
                major.collegeId = collegeId;
                major.collegeName = collegeName;
                majorVirtualList.add(major);
            }
        });
        //生成课程库数据
        for (int i = 0; i < COURSE_NUM; i++) {
            Course course = new Course()
                    .setCourseId((long) (i+1))
                    .setTaskId(TASK_ID)
                    .setBaseCourseId("C-" + (i + 1))
                    .setCourseName("课程" + (i + 1))
                    .setCourseTypeId(COURSE_TYPE)
                    .setCourseType(COURSE_TYPE)
                    .setCourseNature(1)
                    .setMajorProp(1)
                    .setCredit(2.0)
                    .setLectureHour(32)
                    .setExperimentalHour(0)
                    .setComputerHour(0)
                    .setOtherHour(0);
            courseList.add(course);
        }

        //生成教学计划。教学计划相对于一个年级的专业
        AtomicInteger studentName = new AtomicInteger(1);
        majorVirtualList.forEach(majorVirtual -> {
            gradeMap.forEach((gradeId, gradeName) -> {
                //专业
                Major major = new Major()
                        .setTaskId(TASK_ID)
                        .setGradeId(gradeId)
                        .setGradeName(gradeName)
                        .setBaseMajorId(majorVirtual.majorId)
                        .setMajorName(majorVirtual.majorName)
                        .setCollegeId(majorVirtual.collegeId)
                        .setCollegeName(majorVirtual.collegeName)
                        .setCampusId(CAMPUS_NAME)
                        .setCampusName(CAMPUS_NAME)
                        .setCreditLimitMain(30.0)
                        .setCourseLimitMain(10)
                        .setCreditLimitMinor(30.0)
                        .setCourseLimitMinor(10)
                        .setIsEnable(1);
                majorList.add(major);

                //教学计划
                PlanTeaching planTeaching = new PlanTeaching()
                        .setBaseTeachingPlanId("PT-" + majorVirtual.majorId + "-" + gradeId)
                        .setTaskId(TASK_ID)
                        .setGradeId(gradeId)
                        .setGradeName(gradeName)
                        .setBaseMajorId(majorVirtual.majorId)
                        .setMajorName(majorVirtual.majorName)
                        .setMajorVersionName("专业版本")
                        .setStudyNature(1)
                        .setCollegeId(majorVirtual.collegeId)
                        .setCollegeName(majorVirtual.collegeName)
                        .setIsEnable(1);
                planTeachingList.add(planTeaching);

                //学生
                List<Student> studentGroupList = new ArrayList<>();
                for (int i = 0; i < STUDENT_NUM; i++) {
                    Student student = new Student()
                            .setTaskId(TASK_ID)
                            .setGradeId(gradeId)
                            .setGradeName(gradeName)
                            .setMajorId(majorVirtual.majorId)
                            .setMajorName(majorVirtual.majorName)
                            .setCollegeId(majorVirtual.collegeId)
                            .setCollegeName(majorVirtual.collegeName)
                            .setClassId("classId")
                            .setClassName("className")
                            .setSexCode("未知")
                            .setBaseStudentId("S-" + majorVirtual.majorId + "-" + gradeId + (i + 1))
                            .setStudentName("学生" + (studentName.getAndIncrement()))
                            .setSelectionScope(1)
                            .setCreditLimitMain(30.0)
                            .setCourseLimitMain(10)
                            .setCreditLimitMinor(30.0)
                            .setCourseLimitMinor(10);
                    studentGroupList.add(student);
                }
                studentList.addAll(studentGroupList);
                //学生分组
                planStudentVirtualMap.put(planTeaching, studentGroupList);
            });
        });
        //教学计划对应课程。
        planTeachingList.forEach(planTeaching -> {
            for (int i = 0; i < COURSE_NUM; i++) {
                PlanTeachingCourseSegment planTeachingCourseSegment = new PlanTeachingCourseSegment()
                        .setTaskId(TASK_ID)
                        .setBaseTeachingPlanId(planTeaching.getBaseTeachingPlanId())
                        .setBaseCourseId(courseList.get(i).getBaseCourseId())
                        .setFlag(1);
                planTeachingCourseSegmentList.add(planTeachingCourseSegment);
            }
        });
        //教学计划对应学生
        planStudentVirtualMap.forEach((planTeaching, students) -> {
            students.forEach(student -> {
                PlanTeachingStudent planTeachingStudent = new PlanTeachingStudent()
                        .setTaskId(TASK_ID)
                        .setBaseTeachingPlanId(planTeaching.getBaseTeachingPlanId())
                        .setBaseStudentId(student.getBaseStudentId())
                        .setStudyNature(1);
                planTeachingStudentList.add(planTeachingStudent);
            });
        });
        //生成教学班
        courseList.forEach(course -> {
            for (int i = 0; i < TEACHING_CLASS_NUM; i++) {
                TeachingClass teachingClass = new TeachingClass()
                        .setTaskId(TASK_ID)
                        .setTeachingClassName(course.getCourseName() + "-" + (i + 1))
                        .setCourseId(course.getCourseId())
                        .setCollegeId(course.getCollegeId())
                        .setClassNum(CLASS_NUM)
                        .setTeachingClassType(1)
                        .setFlag(1)
                        .setStudyNature(1)
                        .setCampusId(CAMPUS_NAME)
                        .setCampusName(CAMPUS_NAME)
                        .setIsEnable(1);
                teachingClassList.add(teachingClass);
            }
        });
    }

    void insertDatabase(){
        majorMapper.addBatch(majorList);
        planTeachingMapper.addBatch(planTeachingList);

        Consumer<List<Student>> studentConsumer = o -> studentMapper.addBatch(o);
        BatchInsert.batchSplitInsert(studentList, studentConsumer);

        courseMapper.addBatch(courseList);
        planTeachingCourseSegmentMapper.addBatch(planTeachingCourseSegmentList);

        Consumer<List<PlanTeachingStudent>> studentPlanConsumer = o -> planTeachingStudentMapper.addBatch(o);
        BatchInsert.batchSplitInsert(planTeachingStudentList, studentPlanConsumer);

        teachingClassMapper.addBatch(teachingClassList);
        teachingClassService.lambdaUpdate().eq(TeachingClass::getTaskId, TASK_ID)
                .set(TeachingClass::getIsEnable, 1).set(TeachingClass::getClassNum,CLASS_NUM).update();
    }


    @Test
    void insertTask() {
        insertDatabase();
        //任务
        TaskInfo taskInfo = new TaskInfo().setTaskId(TASK_ID).setTerm("2020-202101").setTermName("第一学期").setSchoolId("S-1").setTaskName("测试任务").setWeekSet(1).setMainFlow(1);
        //任务对应年级
        List<TaskToGrade> taskGradeList = new ArrayList<>();
        gradeMap.forEach((gradeId, gradeName) -> {
            TaskToGrade taskToGrade = new TaskToGrade().setTaskId(TASK_ID).setGradeId(gradeId).setGradeName(gradeName);
            taskGradeList.add(taskToGrade);
        });
        //选课任务
        CssTaskInfo cssTaskInfo = new CssTaskInfo().setTaskId(TASK_ID).setCssTaskId(TASK_ID).setType(2).setCssTaskStatus(1);
        //选课轮次
        LocalDateTime now = LocalDateTime.now();
        CssTaskRound cssTaskRound = new CssTaskRound().setId(TASK_ID).setCssTaskId(TASK_ID).setSelectRound(1).setStage(1)
                .setBeginTime(now.plusHours(-1)).setEndTime(now.plusWeeks(1))
                .setStudyNature(1).setMajorProp(1).setCourseNature(3);
        //选课范围 所有年级学生
        List<CssRange> cssRangeList = new ArrayList<>();
        gradeMap.forEach((gradeId, gradeName) -> {
            CssRange cssRange = new CssRange().setTaskId(TASK_ID).setRoundId(TASK_ID)
                    .setOptionId(gradeId).setOptionName(gradeName).setOptionIdentify(2);
            cssRangeList.add(cssRange);
        });
        //设置课程类别
        cssRangeList.add(new CssRange().setTaskId(TASK_ID).setRoundId(TASK_ID)
                .setOptionId(COURSE_TYPE).setOptionName(COURSE_TYPE).setOptionIdentify(3));
        taskInfoService.save(taskInfo);
        taskToGradeService.saveBatch(taskGradeList);
        cssTaskInfoService.save(cssTaskInfo);
        cssTaskRoundService.save(cssTaskRound);
        cssRangeService.saveBatch(cssRangeList);
    }

    @Test
    void preheatingCourseSelection(){
        CssTaskRound cssTaskRound = cssTaskRoundService.getById(1);
        CssTaskInfo cssTaskInfo = cssTaskInfoService.getById(cssTaskRound.getCssTaskId());
        Integer taskId = cssTaskInfo.getTaskId();
        //  1在线选课; 3:预选教学班
        Integer teachingClassType = 1;
        if (cssTaskInfo.getType().equals(1)){
            teachingClassType = 3;
        }
        //获取选课范围 一对多范围设置
        List<CssRange> cssRangeList = cssRangeService.lambdaQuery().eq(CssRange::getRoundId, cssTaskRound.getId()).list();
        List<String> collegeIds = cssRangeList.stream().filter(cssRange -> cssRange.getOptionIdentify().equals(1)).map(CssRange::getOptionId).collect(Collectors.toList());
        List<String> gradeIds = cssRangeList.stream().filter(cssRange -> cssRange.getOptionIdentify().equals(2)).map(CssRange::getOptionId).collect(Collectors.toList());
        //获取该轮次全部学生
        List<Long> studentIds = studentService.lambdaQuery().in(CollUtil.isNotEmpty(collegeIds), Student::getCollegeId, collegeIds)
                .in(CollUtil.isNotEmpty(gradeIds), Student::getGradeId, gradeIds)
                .eq(Student::getTaskId, cssTaskInfo.getTaskId()).list()
                .stream().map(Student::getStudentId).collect(Collectors.toList());
        List<Long> teachingClassIds = new ArrayList<>();
        for (Long studentId : studentIds) {
            Student student = studentService.getById(studentId);
            //获取全部可选教学班
            HashMap<Long, RedisStudentOptionalClass> redisStudentOptionalClassHashMap = studentService.getAvailableTeachingClass(taskId, teachingClassType, student);
            teachingClassIds.addAll(redisStudentOptionalClassHashMap.keySet());
        }
        studentService.getTeachingClassDetail(taskId, teachingClassIds.stream().distinct().collect(Collectors.toList()));
    }


    @Test
    void syncTeachingClassStudent(){
        studentService.syncTeachingClassStudent(TASK_ID);
    }
}
